#include <signal.h>
#include <iostream>
#include <string>
#include <vector>
#include <chrono>
#include <workflow/WFFacilities.h>
#include <workflow/WFTaskFactory.h>
#include <workflow/MySQLResult.h>
#include <ppconsul/agent.h>
#include "CryptoUtil.h"
#include "User.h"
#include "signup.srpc.h"

using std::cout;
using std::endl;
using std::string;
using std::cerr;
using std::vector;

using namespace std::literals;
using namespace srpc;
using namespace protocol;
using ppconsul::Consul;
using namespace ppconsul::agent;

static bool is_exit = false;

class SignupServiceImpl : public Signup::Service
{
public:

	void Register(RegisterRequest *request, RegisterResponse *response, srpc::RPCContext *ctx) override
	{
		// 解析用户名和密码
		User user;
		user.username = request->username();
		user.password = request->password();

#ifdef DEBUG
		cout << "[DEBUG] " << "username = " << user.username << endl;
		cout << "[DEBUG] " << "password = " << user.password << endl;
#endif

		string url = "mysql://root:123@localhost/new";
        user.salt = CryptoUtil::generate_salt();
        string hashPwd = CryptoUtil::hash(user);

        string query = "INSERT INTO tbl_user (username, password, salt) "
                       "VALUES ('" + user.username + "', '" 
                       + hashPwd + "', '" + user.salt + "');";

#ifdef DEBUG
		cout << "[DEBUG] " << query << endl;
#endif

		WFMySQLTask *mysqlTask = WFTaskFactory::create_mysql_task(url, 0, 
		[response](WFMySQLTask *task){
			int state = task->get_state();
			int error = task->get_error();
			if(state != WFT_STATE_SUCCESS)
			{
#ifdef DEBUG
				cout << "[ERROR] " << WFGlobal::get_error_string(state, error);
#endif
				return response->set_message(string{"FAIL"});
			}
			
			MySQLResponse *resp = task->get_resp();
			MySQLResultCursor cursor{resp};
			if(cursor.get_cursor_status() != MYSQL_STATUS_OK || cursor.get_affected_rows() != 1)
			{
#ifdef DEBUG
				cout << "[ERROR] " << "register sql error!" << endl;
#endif
				return response->set_message(string{"FAIL"});
			}

			return response->set_message(string{"SUCCESS"});
		});
		
		mysqlTask->get_req()->set_query(query);
		ctx->get_series()->push_back(mysqlTask);
	}
};

void timerCallback(WFTimerTask *task, Agent &agent)
{
	if(is_exit)
	{
		cout << "Bye!" << endl;
		return;
	}
	agent.servicePass("RegisterService1");

	WFTimerTask *next = WFTaskFactory::create_timer_task(
		9, 
		0, std::bind(timerCallback, std::placeholders::_1, std::ref(agent))
	);
	series_of(task)->push_back(next);
}

static WFFacilities::WaitGroup g_waitGroup(1);

void sig_handler(int signo)
{
	g_waitGroup.done();
	is_exit = true;
}

int main()
{

	signal(SIGINT, sig_handler);

	GOOGLE_PROTOBUF_VERIFY_VERSION;
	srand(clock());	
	unsigned short port = 1412;
	SRPCServer server;

	SignupServiceImpl service;
	server.add_service(&service);

	if(server.start(port) == 0)
	{
		// 指定注册中心 Concul 的ip地址， 端口和数据中心
		Consul consul{"http://127.0.0.1:8500", ppconsul::kw::dc = "dc1"};

		// 创建代理
		Agent agent{consul};

		// 注册服务
		agent.registerService(
			kw::id = "RegisterService1",
			kw::name = "RegisterService",
			kw::address = "127.0.0.1",
			kw::port = 1412,
			kw::check = TtlCheck(10s)
		);

		// 创建定时器任务
		WFTimerTask *timerTask = WFTaskFactory::create_timer_task(
			1, 
			0, 
			std::bind(timerCallback, std::placeholders::_1, std::ref(agent))
		);
		
		// 将任务将入序列
		SeriesWork *series = Workflow::create_series_work(
			timerTask, nullptr 
		);

		series->start();
		g_waitGroup.wait();

		agent.deregisterService("RegisterService1");
		series->cancel();
		server.stop();
	} else {
		cerr << "[ERROR] " << "SRPC server start failed!" << endl;
		exit(1);
	}
	return 0;
}
